package conMgr.ui.papers;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.text.JTextComponent;

import conMgr.model.Review;
import conMgr.model.User;
import conMgr.ui.util.SliderChangeListener;
import conMgr.ui.util.Ui;

/**
 * Provides a view of a review for a paper.
 * @author is4@uw.edu
 */
public class ReviewView extends JPanel
{
	/**
	 * The serialization ID for this class.
	 */
	private static final long serialVersionUID = -6813112492682285516L;
	
	/**
	 * The text box for comments for the author.
	 */
	private final JTextComponent authorCommentTextBox;
	
	/**
	 * The slider for overall rating.
	 */
	private final JSlider overallRatingSlider;
	
	/**
	 * A list of the sliders for individual ratings.
	 */
	private final List<JSlider> ratingsSliders;
	
	/**
	 * The review this view is for.
	 */
	private final Review review;
	
	/**
	 * The text box for comments for the subprogram chair.
	 */
	private final JTextComponent spChairCommentTextBox;
	
	/**
	 * Initializes a new review view.
	 * @param review The review this view is for.
	 */
	public ReviewView(final Review review)
	{
		this.review = review;
		
		setLayout(new GridBagLayout());
		
		int row = 0;
		if (review.getPaper().getAuthor() != User.getCurrentUser())
		{
			addGridBagFieldLabel("Reviewer", row++);
			addGridBagFieldLabel("Comments for\nSubprogram Chair:", row++);
		}
		addGridBagFieldLabel("Comments for\nAuthor:", row++);
		addGridBagFieldLabel("Applicability:", row++);
		addGridBagFieldLabel("Significance:", row++);
		addGridBagFieldLabel("References:", row++);
		addGridBagFieldLabel("Impact Evaluation:", row++);
		addGridBagFieldLabel("Method Appropriateness:", row++);
		addGridBagFieldLabel("Detail:", row++);
		addGridBagFieldLabel("Clarity:", row++);
		addGridBagFieldLabel("Style:", row++);
		addGridBagFieldLabel("Overall Rating:", row++);
		
		ratingsSliders = new LinkedList<JSlider>();
		
		row = 0;
		if (review.getPaper().getAuthor() != User.getCurrentUser())
		{
			addGridBagValueLabel(review.getReviewer().getName(), row++);
			spChairCommentTextBox =
				addGridBagValueTextBox(row++, review.getcommentsForSpChair(), true);
		}
		else
			spChairCommentTextBox = null;
		authorCommentTextBox =
			addGridBagValueTextBox(row++, review.getcommentsForAuthor(), true);
		for (int i = 0; i < 8; i++)
		{
			JSlider slider =
				addGridBagSlider(row++, review.getRating() == null ? 3 : review.getRating().get(i));
			ratingsSliders.add(slider);
		}
		
		overallRatingSlider =
			addGridBagSlider(row++, review.getOverallRatings() == null ? 3 : review.getOverallRatings());
	}

	/**
	 * Adds a new field label to a grid bag.
	 * @param text The text to display in the label.
	 * @param row The row of the grid that the label belongs in.
	 */
	private void addGridBagFieldLabel(final String text, final int row)
	{
		String theText;
		
		if (text.contains("\n"))
			theText = "<html>" + text.replace("\n", "<br />") + "</html>";
		else
			theText = text;
		
		final JLabel label = new JLabel(theText);
		final GridBagConstraints constraints = new GridBagConstraints();
		constraints.gridx = 0;
		constraints.gridy = row;
		constraints.anchor = GridBagConstraints.NORTHWEST;
		constraints.insets = Ui.DEFAULT_INSETS;
		add(label, constraints);
	}
	
	/**
	 * Adds a new slider to a grid bag.
	 * @param row The row of the grid that the text box belongs in.
	 * @param value The value to display.
	 * @return The new slider.
	 */
	private JSlider addGridBagSlider(final int row, final int value)
	{
		final JSlider slider =
			new JSlider(JSlider.HORIZONTAL, 1, 5, value);
		slider.setMajorTickSpacing(1);
		slider.setMinorTickSpacing(1);
		slider.setPaintTicks(true);
		
		if
		(
			review.getIsSubmitted() ||
			review.getReviewer() != User.getCurrentUser()
		)
			slider.setEnabled(false);
		
		GridBagConstraints constraints = new GridBagConstraints();
		constraints.gridx = 1;
		constraints.gridy = row;
		constraints.anchor = GridBagConstraints.WEST;
		constraints.insets = Ui.DEFAULT_INSETS;
		add(slider, constraints);
		
		final JLabel label = new JLabel(Integer.toString(slider.getValue()));
		constraints = new GridBagConstraints();
		constraints.gridx = 2;
		constraints.gridy = row;
		constraints.anchor = GridBagConstraints.WEST;
		constraints.insets = Ui.DEFAULT_INSETS;
		add(label, constraints);
		
		slider.addChangeListener(new SliderChangeListener(slider, label));
		
		return slider;
	}
	
	/**
	 * Adds a new value label to a grid bag.
	 * @param text The text to display in the label.
	 * @param row The row of the grid that the label belongs in.
	 */
	private void addGridBagValueLabel(final String text, final int row)
	{
		final JLabel label = new JLabel(text);
		label.setFont(Ui.getUnboldFont(label.getFont()));
		
		final GridBagConstraints constraints = new GridBagConstraints();
		constraints.gridx = 1;
		constraints.gridwidth = 2;
		constraints.gridy = row;
		constraints.anchor = GridBagConstraints.NORTHWEST;
		constraints.insets = Ui.DEFAULT_INSETS;
		add(label, constraints);
	}
	
	/**
	 * Adds a new empty text box to a grid bag.
	 * @param row The row of the grid that the text box belongs in.
	 * @param text The text to put in the text box.
	 * @return The newly-created text box.
	 */
	private JTextComponent addGridBagValueTextBox
	(
		final int row,
		final String text,
		boolean large
	)
	{
		JComponent addControl;
		JTextComponent field;
		
		if (large)
		{
			final JTextArea textArea = new JTextArea(text, 5, 30);
			textArea.setLineWrap(true);
			textArea.setWrapStyleWord(true);
			field = textArea;
			
			addControl = new JScrollPane(textArea);
		}
		else
			addControl = field = new JTextField(text, 30);
		
		if
		(
			review.getIsSubmitted() ||
			review.getReviewer() != User.getCurrentUser()
		)
		{
			field.setEditable(false);
			field.setBackground(Color.WHITE);
		}
		
		final GridBagConstraints constraints = new GridBagConstraints();
		constraints.gridx = 1;
		constraints.gridwidth = 2;
		constraints.gridy = row;
		constraints.anchor = GridBagConstraints.NORTHWEST;
		constraints.fill = GridBagConstraints.HORIZONTAL;
		constraints.insets = Ui.DEFAULT_INSETS;
		add(addControl, constraints);
		
		return field;
	}
	
	/**
	 * Submits this review, if applicable.
	 * @return True if the review was submitted successfully; otherwise, false.
	 */
	public boolean save()
	{
		if (review.getReviewer() != User.getCurrentUser())
			return true;
		
		final String spChairComments = spChairCommentTextBox.getText();
		final String authorComments = authorCommentTextBox.getText();
		
		if (Ui.isBlank(spChairComments) || Ui.isBlank(authorComments))
		{
			JOptionPane.showMessageDialog
			(
				null,
				"Please fill out all of the fields. A review cannot be submitted with missing information.",
				"Cannot Submit Review",
				JOptionPane.ERROR_MESSAGE
			);
			return false;
		}
		
		List<Integer> ratings = new ArrayList<Integer>();
		
		for (JSlider slider : ratingsSliders)
			ratings.add(slider.getValue());
		
		review.submitToSubprogramChair
		(
			authorComments,
			spChairComments,
			ratings,
			overallRatingSlider.getValue()
		);
		
		return true;
	}
}
